Skip to content

feat(sensing-server): wire the ADR-302 OOD gate into the live loop - #1728

Open
fallen-pc wants to merge 1 commit into
ruvnet:mainfrom
fallen-pc:feat/ood-gate-live-wiring
Open

feat(sensing-server): wire the ADR-302 OOD gate into the live loop#1728
fallen-pc wants to merge 1 commit into
ruvnet:mainfrom
fallen-pc:feat/ood-gate-live-wiring

Conversation

@fallen-pc

Copy link
Copy Markdown

Summary

RuView's entire ADR-300 honesty substrate — ruview-witness, ruview-attest, ruview-certify, ruview-groundtruth, ruview-scorecard, and ruview-ood — compiles and passes its own unit tests, but none of it was reachable from anything that actually runs. wifi-densepose-sensing-server depended on zero of these six crates. A live classification could report person_present with no domain-generalization check at all, no matter how far the room had drifted from whatever it was tuned on.

This PR wires the first strand: an opt-in --calibration-certificate <path> flag that loads and verifies an ADR-301 calibration certificate at startup, then gates every live cycle KNOWN/DEGRADED/UNKNOWN against it via ruview-ood, publishing the result as domain_state on /ws/sensing and /api/v1/sensing/latest. Unset by default — existing behavior is unchanged.

Fails closed

A certificate that doesn't load, doesn't parse, or doesn't verify aborts startup rather than silently running ungated. WDP_CALIBRATION_KEY_ID/WDP_CALIBRATION_KEY_SECRET are required env vars when the flag is set.

Two honest, documented limitations — not glossed over

  1. The live fingerprint is a documented approximation, not enrolled-bank rigor. Live-verifying against a hand-minted certificate whose fingerprint was deliberately chosen to closely match the live feed's own observed scalars still produced distance.total ≈ 0.9 (envelope outer threshold is 0.15). The live approximation's raw dBm/variance units evidently don't sit on the scale RoomFingerprint::distance's constants were tuned for (real enrolled-bank statistics). Practical effect: expect DEGRADED/UNKNOWN far more often than a real per-room bank would produce, even for a genuinely fine room, until this is addressed (rescaled live fingerprint, or better: keep the enrolled-bank fingerprint live-updated instead of approximating).
  2. The fourth ADR-302 input (model uncertainty) has nothing honest to report — the live classifier is heuristic, not a model with a calibrated uncertainty head. Fixed at 0.0 (documented, never escalates the gate) rather than fabricated. Signal quality gets the same treatment at the two ESP32 ingest call sites (no independent live coherence/SNR scalar there either).

Also not solved: minting a real certificate still requires the offline wifi-densepose-cli calibrate/enroll/train-room pipeline (ADR-151) — this module only consumes a certificate.

Test plan

  • cargo test -p wifi-densepose-sensing-server --no-default-features — full suite green (529 lib + 253 bin + others), including 6 new ood_gate tests: fresh-certificate KNOWN, expired-certificate UNKNOWN (confidence suppressed per ADR-300 rule 1), device-mismatch UNKNOWN, live-fingerprint determinism, fail-closed on missing file, fail-closed on missing key env vars
  • npx @ruvnet/ruview claim-check on this PR body — PASS
  • Live-verified end to end against the real running server (--source simulated):
    • A hand-minted, correctly-signed certificate loads and verifies at startup (ADR-302 OOD gate: loaded and verified ... in the log)
    • An empty-baseline certificate against real simulated CSI correctly reports Unknown(DriftBeyondEnvelope) with class/confidence suppressed (null) and a Required recalibration signal
    • A certificate with a closely-matched fingerprint reduces the measured distance but still correctly stays UNKNOWN rather than crossing into a false KNOWN — see limitation 1 above

RuView's entire ADR-300 honesty substrate - witness chains,
authenticated sensor identity, capability certificates, domain-
generalization scorecards, and this OOD gate - compiled and passed
its own unit tests but was completely unreachable from anything that
actually runs. wifi-densepose-sensing-server depended on none of the
six crates. A live classification could report person_present with
zero domain-generalization check, no matter how far the room had
drifted from whatever it was tuned on.

This wires the first strand: an opt-in --calibration-certificate
<path> flag that loads and verifies an ADR-301 calibration certificate
at startup (fails closed - a certificate that doesn't load or verify
aborts startup, never runs silently ungated), then gates every live
cycle KNOWN/DEGRADED/UNKNOWN against it via ruview-ood, publishing the
result as domain_state on /ws/sensing and /api/v1/sensing/latest.
Unset by default - existing behavior is unchanged.

Two honest, documented limitations, not silently glossed over:

1. The live fingerprint fed to the gate (live_fingerprint_from_stats)
   is a proxy built from scalars the live loop already tracks
   (mean_rssi, variance, motion_band_power), not the enrolled-bank
   rigor of RoomFingerprint::from_bank. Live-verifying this against a
   hand-minted certificate whose fingerprint was chosen to closely
   match the live feed's own observed scalars still produced
   distance.total around 0.9 (envelope outer threshold is 0.15) - the
   live approximation's raw units evidently don't sit on the scale
   RoomFingerprint::distance's constants were tuned for. Expect
   DEGRADED/UNKNOWN more often than a real per-room bank would
   produce, even for a genuinely fine room, until this is addressed.

2. The fourth ADR-302 input (model uncertainty) has nothing honest to
   report - the live classifier is heuristic, not a model with a
   calibrated uncertainty head. Fixed at 0.0 (documented, never
   escalates the gate) rather than fabricated. Same treatment for
   signal quality at the two ESP32 ingest call sites, which have no
   independent live coherence/SNR scalar either.

Also NOT solved: minting a real certificate still requires the
offline wifi-densepose-cli calibrate/enroll/train-room pipeline
(ADR-151) - this module only consumes a certificate. And the
cross-domain rucelium-style zone-pairing question doesn't apply here
(that was a different repo/investigation) - this is single-room,
same-source gating only.

New tests: fresh-certificate KNOWN path, expired-certificate UNKNOWN
path (confidence suppressed per ADR-300 rule 1), device-mismatch
UNKNOWN path, live-fingerprint determinism, fail-closed on a missing
file, fail-closed on missing key env vars.

Live-verified end to end against the real running server: a
hand-minted, correctly-signed certificate loads and verifies at
startup; an empty-baseline certificate against real simulated CSI
correctly reports Unknown(DriftBeyondEnvelope) with class/confidence
suppressed and a Required recalibration signal; a certificate with a
closely-matched fingerprint reduces the measured distance but still
correctly stays UNKNOWN (documented limitation 1 above) rather than
crossing into a false KNOWN.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant